# -*- coding: utf-8 -*-
"""
HTML表格组件 - 美观的网页表格
"""
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtWidgets import QVBoxLayout
from PySide6.QtCore import Signal, Slot, QObject
from PySide6.QtWebEngineCore import QWebEnginePage
from PySide6.QtWebChannel import QWebChannel
from ..base.widget import TgBaseWidget
from typing import List, Dict, Union, Any
import json


# JS通信桥
class Bridge(QObject):
    js_row_double_clicked = Signal(int)
    js_sort_changed = Signal(int, str)
    js_scroll_changed = Signal(int, int)

    @Slot(int)
    def on_row_double_clicked(self, row_index):
        self.js_row_double_clicked.emit(row_index)
    @Slot(int, str)
    def on_sort_changed(self, col_index, sort_direction):
        self.js_sort_changed.emit(col_index, sort_direction)
    @Slot(int, int)
    def on_scroll_changed(self, scroll_left, scroll_top):
        self.js_scroll_changed.emit(scroll_left, scroll_top)


class TgHtmlTable(TgBaseWidget):
    """
    HTML表格组件 - 一个功能丰富、样式美观的基于QWebEngineView的表格组件。

    主要功能:
    - 动态数据加载和更新
    - 可自定义的列排序 (点击表头)
    - 可调整列宽
    - 对特定列应用红/绿盈亏样式
    - 在单元格内嵌入SVG小型折线图 (走势图)
    - 行选择和点击事件 (待实现信号桥接)
    - 现代化的UI设计，包括悬停效果、圆角、阴影等

    使用方法:
    1. 创建 `TgHtmlTable` 实例。
    2. 使用 `update_data(headers, data)` 或 `set_data(headers, data)` 方法填充数据。
    3. (可选) 使用 `set_profit_loss_style()` 为指定列设置盈亏样式。
    4. (可选) 使用 `set_chart_column()` 为指定列设置走势图。

    走势图数据格式:
    要为某一列显示走势图，你需要:
    a) 调用 `set_chart_column("列名", config_dict)`。
    b) 确保该列的数据是以下格式之一:
       - **数字列表或元组**: `[10, 12, 11, 15, 14]`
       - **逗号分隔的字符串**: `"10,12,11,15,14"`
    
    如果提供的是单个数字，组件会为其生成一段随机的走势数据。

    示例:
    ```python
    # 1. 创建组件
    self.table = TgHtmlTable()

    # 2. 准备数据
    headers = ["名称", "价格", "涨跌幅", "近期走势"]
    data = [
        ["股票A", 10.5, 1.25, "10.1,10.2,10.0,10.4,10.5"],  # 字符串格式
        ["股票B", 25.8, -2.1, [26.5, 26.3, 26.8, 25.9, 25.8]], # 列表格式
        ["股票C", 5.2, 0.5, 5.2] # 单个值，将生成随机走势
    ]
    self.table.update_data(headers, data)

    # 3. 设置样式和图表
    self.table.set_profit_loss_style(["涨跌幅"])
    
    chart_config = {
        'width': 120,
        'height': 35,
        'positive_color': '#f44336', # 上涨为红色
        'negative_color': '#4caf50', # 下跌为绿色
    }
    self.table.set_chart_column("近期走势", chart_config)
    ```
    """
    
    # 信号定义
    cell_clicked = Signal(int, int)  # 行，列
    cell_double_clicked = Signal(int, int)  # 行，列
    row_selected = Signal(int)  # 选中的行索引
    row_double_clicked = Signal(dict)  # 双击行事件，返回整行数据字典
    
    def __init__(self, headers=None, data=None, parent=None, cell_size='medium'):
        super().__init__(parent)
        """
        初始化HTML表格组件。

        Args:
            headers (List[str], optional): 表头列表. Defaults to None.
            data (List[List[Any]], optional): 表格数据. Defaults to None.
            parent (QWidget, optional): 父组件. Defaults to None.
        """
        # 表格数据
        self.headers = headers or []
        self.data = data or []
        
        # 样式配置
        self._profit_loss_columns = set()
        self._use_gradient = False
        self._color_type = 'font'
        self._sorting_enabled = True
        self._column_resize_mode = 'resizable'
        self._chart_columns = {}  # 存储图表列的配置
        self._hidden_columns = set()  # 存储隐藏列的索引
        # cell_size can be 'small', 'medium', or 'large'
        self._cell_size = cell_size if cell_size in ('small', 'medium', 'large') else 'medium'
        
        # 创建Web视图
        self.webview = None
        self.bridge = Bridge()
        self._scroll_x = 0
        self._scroll_y = 0
        
        # persistent sort state
        self._current_sort_column = -1
        self._current_sort_direction = 'asc'
        # connect JS sort change signal
        self.bridge.js_sort_changed.connect(self._on_js_sort_changed)
        self.bridge.js_scroll_changed.connect(self._on_js_scroll_changed)
        
        # 初始化组件
        self.initialize()
    
    def setup_ui(self):
        """初始化UI"""
        self.webview = QWebEngineView()
        
        # 设置JS通信
        self.page = QWebEnginePage(self)
        self.channel = QWebChannel(self.page)
        self.page.setWebChannel(self.channel)
        self.channel.registerObject("bridge", self.bridge)
        self.webview.setPage(self.page)
        # Reapply sort state after HTML reload
        self.webview.loadFinished.connect(self._on_load_finished)
        
        # 连接信号
        self.bridge.js_row_double_clicked.connect(self._on_row_double_clicked)
        
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.webview)
        
        # 生成并加载HTML
        self._render_table()
    
    def _render_table(self):
        """渲染HTML表格"""
        html_content = self._generate_html()
        self.webview.setHtml(html_content)
    
    def _generate_html(self) -> str:
        """生成HTML表格代码"""
        return f"""
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>HTML Table</title>
    <script src="qrc:///qtwebchannel/qwebchannel.js"></script>
    <style>
        {self._get_css_styles()}
    </style>
</head>
<body>
    <div class="table-container size-{self._cell_size}">
        <table id="dataTable" class="modern-table">
            <thead>
                <tr>
                    {self._generate_header_html()}
                </tr>
            </thead>
            <tbody>
                {self._generate_body_html()}
            </tbody>
        </table>
    </div>
    
    <script>
        // Persisted sort state from Python
        var initialSortColumn = {self._current_sort_column};
        var initialSortDirection = '{self._current_sort_direction}';
        // Restore scroll position before table initialization
        var initialScrollLeft = {self._scroll_x};
        var initialScrollTop = {self._scroll_y};
        {self._get_javascript()}
        document.addEventListener('DOMContentLoaded', function() {{
            var container = document.querySelector('.table-container');
            if (container) {{
                container.scrollLeft = initialScrollLeft;
                container.scrollTop = initialScrollTop;
            }}
            window.modernTable = new ModernTable();
            // Apply initial sort state including visual indicators
            if (typeof initialSortColumn !== 'undefined' && initialSortColumn >= 0) {{
                window.modernTable.sortColumn = initialSortColumn;
                window.modernTable.sortDirection = initialSortDirection;
                window.modernTable.updateHeaderStyles();
            }}
        }});
    </script>
</body>
</html>
        """
    
    def _get_css_styles(self) -> str:
        """获取CSS样式"""
        base_css = """
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            background-color: #f5f5f5;
            color: #333;
            font-size: 14px;
        }
        
        .table-container {
            width: 100%;
            height: 100vh;
            overflow: auto;
            background: white;
            border-radius: 8px;
            box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
        }
        
        .modern-table {
            width: 100%;
            border-collapse: collapse;
            background: white;
            border-radius: 8px;
            overflow: hidden;
        }
        
        .modern-table thead {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            position: sticky;
            top: 0;
            z-index: 10;
        }
        
        .modern-table th {
            padding: 12px 16px;
            text-align: left;
            font-weight: 600;
            font-size: 13px;
            letter-spacing: 0.5px;
            text-transform: uppercase;
            cursor: pointer;
            position: relative;
            border-right: 1px solid rgba(255, 255, 255, 0.2);
            transition: background-color 0.2s ease;
        }
        
        .modern-table th:hover {
            background-color: rgba(255, 255, 255, 0.1);
        }
        
        .modern-table th.sortable {
            position: relative;
            padding-right: 32px;
        }
        
        .modern-table th.sortable:after {
            content: "↕";
            position: absolute;
            right: 8px;
            top: 50%;
            transform: translateY(-50%);
            opacity: 0.6;
            font-size: 14px;
            font-weight: bold;
        }
        
        .modern-table th.sort-asc:after {
            content: "▲";
            opacity: 1;
            color: #ffeb3b;
            font-size: 12px;
        }
        
        .modern-table th.sort-desc:after {
            content: "▼";
            opacity: 1;
            color: #ffeb3b;
            font-size: 12px;
        }
        
        .modern-table th.resizable {
            resize: horizontal;
            overflow: hidden;
            min-width: 80px;
        }
        
        .modern-table tbody tr {
            border-bottom: 1px solid #e0e0e0;
            transition: all 0.2s ease;
        }
        
        .modern-table tbody tr:hover {
            background-color: #f8f9ff;
            transform: translateY(-1px);
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
        }
        
        .modern-table tbody tr.selected {
            background-color: #e3f2fd;
            border-left: 4px solid #2196f3;
        }
        
        .modern-table td {
            padding: 12px 16px;
            border-right: 1px solid #f0f0f0;
            vertical-align: middle;
            transition: all 0.2s ease;
        }
        
        .modern-table td:last-child,
        .modern-table th:last-child {
            border-right: none;
        }
        
        /* 盈亏样式 */
        .profit {
            color: #d32f2f;
            font-weight: 600;
        }
        
        .loss {
            color: #388e3c;
            font-weight: 600;
        }
        
        .neutral {
            color: #666;
        }
        
        /* 背景色盈亏样式 */
        .profit-bg {
            background-color: #d32f2f;
            color: white;
            font-weight: 600;
        }
        
        .loss-bg {
            background-color: #388e3c;
            color: white;
            font-weight: 600;
        }
        
        .neutral-bg {
            background-color: #f5f5f5;
            color: #666;
        }
        
        /* 行号样式 */
        .row-number {
            background-color: #f5f5f5;
            color: #999;
            font-size: 12px;
            text-align: center;
            font-weight: 500;
        }
        
        /* 滚动条样式 */
        .table-container::-webkit-scrollbar {
            width: 8px;
            height: 8px;
        }
        
        .table-container::-webkit-scrollbar-track {
            background: #f1f1f1;
            border-radius: 4px;
        }
        
        .table-container::-webkit-scrollbar-thumb {
            background: #c1c1c1;
            border-radius: 4px;
        }
        
        .table-container::-webkit-scrollbar-thumb:hover {
            background: #a8a8a8;
        }
        
        /* 内嵌图表样式 */
        .mini-chart {
            width: 100px;
            height: 30px;
            display: inline-block;
            vertical-align: middle;
            margin: 0 4px;
        }
        
        .mini-chart svg {
            width: 100%;
            height: 100%;
        }
        
        .chart-cell {
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .chart-value {
            font-weight: 600;
            min-width: 60px;
        }
        
        /* 响应式设计 */
        @media (max-width: 768px) {
            .modern-table {
                font-size: 12px;
            }
            
            .modern-table th,
            .modern-table td {
                padding: 8px 12px;
            }
            
            .mini-chart {
                width: 80px;
                height: 25px;
            }
        }
        """
        # Cell size variation CSS will be appended
        cell_size_css = """
        /* Cell size variations */
        .size-small .modern-table th, .size-small .modern-table td {
            padding: 4px 8px;
            font-size: 12px;
        }
        .size-medium .modern-table th, .size-medium .modern-table td {
            padding: 12px 16px;
            font-size: 14px;
        }
        .size-large .modern-table th, .size-large .modern-table td {
            padding: 20px 24px;
            font-size: 16px;
        }
        """
        # append gradient styles if using gradient
        gradient_css = self._generate_gradient_css() if self._use_gradient else ""
        return base_css + gradient_css + cell_size_css
    
    def _generate_header_html(self) -> str:
        """生成表头HTML"""
        if not self.headers:
            return ""
        
        header_cells = []
        for i, header in enumerate(self.headers):
            if i in self._hidden_columns:
                continue
            
            css_classes = []
            if self._sorting_enabled:
                css_classes.append("sortable")
            if self._column_resize_mode == 'resizable':
                css_classes.append("resizable")
            
            class_attr = f' class="{" ".join(css_classes)}"' if css_classes else ""
            header_cells.append(f'<th data-column="{i}"{class_attr}>{header}</th>')
        
        return "\n".join(header_cells)
    
    def _generate_body_html(self) -> str:
        """生成表体HTML"""
        if not self.data:
            return '<tr><td colspan="100%" style="text-align: center; color: #999; padding: 40px;">加载中</td></tr>'
        
        rows = []
        for row_idx, row_data in enumerate(self.data):
            cells = []
            for col_idx, cell_value in enumerate(row_data):
                if col_idx in self._hidden_columns:
                    continue
                
                css_classes = []
                cell_content = ""
                
                # 检查是否为图表列
                if col_idx in self._chart_columns:
                    chart_config = self._chart_columns[col_idx]
                    cell_content = self._generate_chart_cell(cell_value, chart_config, row_idx, col_idx)
                    css_classes.append("chart-cell")
                else:
                    cell_text = str(cell_value)
                    
                    # 应用盈亏样式
                    if col_idx in self._profit_loss_columns:
                        try:
                            num_val = float(str(cell_value).replace('%', '').replace(',', ''))
                            if self._use_gradient:
                                # 使用渐变效果，基于绝对值计算颜色强度
                                style_class = self._get_gradient_style_class(num_val, row_idx, col_idx)
                                if style_class:
                                    css_classes.append(style_class)
                            else:
                                # 传统样式
                                suffix = "-bg" if self._color_type == 'background' else ""
                                if num_val > 0:
                                    css_classes.append(f"profit{suffix}")
                                elif num_val < 0:
                                    css_classes.append(f"loss{suffix}")
                                else:
                                    css_classes.append(f"neutral{suffix}")
                        except (ValueError, TypeError):
                            pass
                    
                    cell_content = cell_text
                
                class_attr = f' class="{" ".join(css_classes)}"' if css_classes else ""
                cells.append(f'<td data-row="{row_idx}" data-col="{col_idx}"{class_attr}>{cell_content}</td>')
            
            row_class = f'data-row-{row_idx}'
            rows.append(f'<tr class="{row_class}" data-row="{row_idx}">{"".join(cells)}</tr>')
        
        return "\n".join(rows)
    
    def _generate_chart_cell(self, cell_value, chart_config, row_idx, col_idx):
        """生成包含图表的单元格HTML"""
        try:
            # 解析数据
            if isinstance(cell_value, (list, tuple)):
                # 如果是数组，直接使用
                data_points = list(cell_value)
                current_value = data_points[-1] if data_points else 0
            elif isinstance(cell_value, str) and ',' in cell_value:
                # 如果是逗号分隔的字符串，解析为数组
                data_points = [float(x.strip()) for x in cell_value.split(',')]
                current_value = data_points[-1] if data_points else 0
            else:
                # 单个数值，生成简单的示例数据
                try:
                    current_value = float(str(cell_value).replace('%', '').replace(',', ''))
                except ValueError:
                    current_value = 50.0  # 默认值
                    
                # 生成简单的随机走势数据
                import random
                data_points = []
                base_value = current_value * 0.95  # 从稍低的值开始
                for i in range(10):
                    variation = random.uniform(-0.05, 0.05) * base_value
                    base_value += variation
                    data_points.append(base_value)
                data_points[-1] = current_value  # 确保最后一个值是当前值
            
            # 生成SVG图表
            chart_svg = self._generate_mini_chart_svg(data_points, chart_config)
            
            # 格式化当前值
            value_text = f"{current_value:.2f}"
            if chart_config.get('show_percent', False):
                value_text += "%"
            
            # 应用盈亏样式到数值 - 比较第一个和最后一个值
            value_class = ""
            if len(data_points) >= 2:
                change = data_points[-1] - data_points[0]
                if change > 0:
                    value_class = "profit"
                elif change < 0:
                    value_class = "loss"
                else:
                    value_class = "neutral"
            
            html_result = f'''
                <div class='chart-cell'>
                    <span class='chart-value {value_class}'>{value_text}</span>
                    <div class='mini-chart' style='width: {chart_config.get('width',100)}px; height: {chart_config.get('height',30)}px;'>{chart_svg}</div>
                </div>
            '''
            return html_result
            
        except Exception:
            # 如果生成图表失败，返回原始值
            return str(cell_value)
    
    def _generate_mini_chart_svg(self, data_points, chart_config):
        """生成小型SVG折线图"""
        if not data_points or len(data_points) < 2:
            return '<svg></svg>'
        
        width = chart_config.get('width', 100)
        height = chart_config.get('height', 30)
        
        # 计算数据范围
        min_val = min(data_points)
        max_val = max(data_points)
        
        # 避免除零错误
        if max_val == min_val:
            max_val = min_val + 1
        
        # 计算坐标点
        points = []
        for i, value in enumerate(data_points):
            x = (i / (len(data_points) - 1)) * (width - 10) + 5  # 留5px边距
            y = height - 5 - ((value - min_val) / (max_val - min_val)) * (height - 10)  # 留5px边距
            points.append(f"{x:.1f},{y:.1f}")
        
        polyline_points = " ".join(points)
        
        # 确定线条颜色
        line_color = chart_config.get('color', '#2196f3')
        if data_points[-1] > data_points[0]:
            line_color = chart_config.get('positive_color', '#4caf50')  # 绿色上涨
        elif data_points[-1] < data_points[0]:
            line_color = chart_config.get('negative_color', '#f44336')  # 红色下跌
        
        # 生成SVG
        svg_content = f'<svg viewBox="0 0 {width} {height}" xmlns="http://www.w3.org/2000/svg"><polyline points="{polyline_points}" fill="none" stroke="{line_color}" stroke-width="{chart_config.get("stroke_width",1)}" stroke-linecap="round" stroke-linejoin="round"/><circle cx="{points[0].split(",")[0]}" cy="{points[0].split(",")[1]}" r="2" fill="{line_color}" opacity="0.7"/><circle cx="{points[-1].split(",")[0]}" cy="{points[-1].split(",")[1]}" r="2" fill="{line_color}"/></svg>'
        return svg_content
    
    def _get_gradient_style_class(self, num_val, row_idx, col_idx):
        """生成渐变样式类名"""
        if num_val == 0:
            return "gradient-neutral"
        
        # 计算颜色强度 (0-1)，基于绝对值
        # 这里可以根据数据范围调整，暂时使用简单的算法
        abs_val = abs(num_val)
        intensity = min(abs_val / 10.0, 1.0)  # 假设10为最大强度值，可调整
        
        # 将强度转换为离散等级 (0-9)
        level = int(intensity * 9)
        
        if num_val > 0:
            return f"gradient-positive-{level}"
        else:
            return f"gradient-negative-{level}"
    
    def _generate_gradient_css(self):
        """生成渐变CSS样式"""
        styles = []
        
        # 生成正值(红色)渐变样式
        for i in range(10):
            alpha = (i + 1) / 10.0  # 0.1 到 1.0
            if self._color_type == 'background':
                # 背景色渐变，文字为白色或黑色
                text_color = "#ffffff" if alpha > 0.5 else "#000000"
                styles.append(f"""
        .gradient-positive-{i} {{
            background-color: rgba(244, 67, 54, {alpha:.1f});
            color: {text_color};
            font-weight: 600;
        }}""")
            else:
                # 字体色渐变
                styles.append(f"""
        .gradient-positive-{i} {{
            color: rgba(244, 67, 54, {alpha:.1f});
            font-weight: 600;
        }}""")
        
        # 生成负值(绿色)渐变样式
        for i in range(10):
            alpha = (i + 1) / 10.0  # 0.1 到 1.0
            if self._color_type == 'background':
                # 背景色渐变，文字为白色或黑色
                text_color = "#ffffff" if alpha > 0.5 else "#000000"
                styles.append(f"""
        .gradient-negative-{i} {{
            background-color: rgba(76, 175, 80, {alpha:.1f});
            color: {text_color};
            font-weight: 600;
        }}""")
            else:
                # 字体色渐变
                styles.append(f"""
        .gradient-negative-{i} {{
            color: rgba(76, 175, 80, {alpha:.1f});
            font-weight: 600;
        }}""")
        
        # 中性值样式
        if self._color_type == 'background':
            styles.append("""
        .gradient-neutral {
            background-color: #ffffff;
            color: #666;
        }""")
        else:
            styles.append("""
        .gradient-neutral {
            color: #666;
        }""")
        
        return "\n".join(styles)
    
    def _get_javascript(self) -> str:
        """获取JavaScript代码"""
        return """
        // 设置与Python的通信桥
        new QWebChannel(qt.webChannelTransport, function (channel) {
            window.bridge = channel.objects.bridge;
        });

        class ModernTable {
            constructor() {
                this.sortColumn = -1;
                this.sortDirection = 'asc';
                this.selectedRow = -1;
                this.init();
            }
            
            init() {
                this.bindEvents();
            }
            
            bindEvents() {
                // 移除所有现有的事件监听器，避免重复绑定
                this.removeEvents();
                
                // 表头点击排序 - 使用bind确保this上下文正确
                const headers = document.querySelectorAll('th.sortable');
                headers.forEach((header, index) => {
                    const clickHandler = () => {
                        this.sortByColumn(index);
                    };
                    header.addEventListener('click', clickHandler);
                    // 保存引用以便后续移除
                    header._clickHandler = clickHandler;
                });
                
                // 行点击选择
                const rows = document.querySelectorAll('tbody tr');
                rows.forEach((row, index) => {
                    const clickHandler = (e) => {
                        this.selectRow(index);
                        const rowIndex = parseInt(row.dataset.row);
                        const colIndex = e.target.dataset.col ? parseInt(e.target.dataset.col) : -1;
                        this.onCellClick(rowIndex, colIndex);
                    };
                    
                    const dblClickHandler = (e) => {
                        const rowIndex = parseInt(row.dataset.row);
                        const colIndex = e.target.dataset.col ? parseInt(e.target.dataset.col) : -1;
                        this.onCellDoubleClick(rowIndex, colIndex);
                    };
                    
                    row.addEventListener('click', clickHandler);
                    row.addEventListener('dblclick', dblClickHandler);
                    
                    // 保存引用以便后续移除
                    row._clickHandler = clickHandler;
                    row._dblClickHandler = dblClickHandler;
                });
            }
            
            removeEvents() {
                // 移除表头事件
                const headers = document.querySelectorAll('th.sortable');
                headers.forEach(header => {
                    if (header._clickHandler) {
                        header.removeEventListener('click', header._clickHandler);
                        delete header._clickHandler;
                    }
                });
                
                // 移除行事件
                const rows = document.querySelectorAll('tbody tr');
                rows.forEach(row => {
                    if (row._clickHandler) {
                        row.removeEventListener('click', row._clickHandler);
                        delete row._clickHandler;
                    }
                    if (row._dblClickHandler) {
                        row.removeEventListener('dblclick', row._dblClickHandler);
                        delete row._dblClickHandler;
                    }
                });
            }
            
            sortByColumn(columnIndex) {
                if (!this.isSortingEnabled()) return;
                
                const table = document.getElementById('dataTable');
                const tbody = table.querySelector('tbody');
                const rows = Array.from(tbody.querySelectorAll('tr'));
                
                // 更新排序方向
                if (this.sortColumn === columnIndex) {
                    this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
                } else {
                    this.sortColumn = columnIndex;
                    this.sortDirection = 'asc';
                }
                
                // 更新表头样式
                this.updateHeaderStyles();
                
                // 排序数据
                rows.sort((a, b) => {
                    const aValue = this.getCellValue(a, columnIndex);
                    const bValue = this.getCellValue(b, columnIndex);
                    
                    const result = this.compareValues(aValue, bValue);
                    const finalResult = this.sortDirection === 'asc' ? result : -result;
                    return finalResult;
                });
                
                // 重新插入排序后的行
                tbody.innerHTML = '';
                rows.forEach(row => tbody.appendChild(row));
                
                // 重新绑定事件
                this.bindEvents();
                    // Notify Python of sort change
                    if (window.bridge && window.bridge.on_sort_changed) {
                        window.bridge.on_sort_changed(this.sortColumn, this.sortDirection);
                    }
            }
            
            getCellValue(row, columnIndex) {
                const cell = row.children[columnIndex];
                if (!cell) return '';
                
                const text = cell.textContent.trim();
                
                // 尝试解析为数字，支持百分号、千分位分隔符等
                let sanitized = text;
                
                // 移除百分号、千分位分隔符、空格等，但保留正负号和小数点
                sanitized = sanitized.replace(/[%,\s]/g, '');
                
                // 检查是否为有效数字（包括带正负号的）
                const numMatch = sanitized.match(/^([+-]?\d*\.?\d+)$/);
                if (numMatch) {
                    const num = parseFloat(numMatch[1]);
                    if (!isNaN(num)) {
                        return num;
                    }
                }
                
                // 如果不是数字，返回原始文本用于字符串比较
                return text.toLowerCase();
            }
            
            compareValues(a, b) {
                // 如果两个都是数字，按数字比较
                if (typeof a === 'number' && typeof b === 'number') {
                    return a - b;
                }
                
                // 如果一个是数字一个不是，数字排在前面
                if (typeof a === 'number' && typeof b !== 'number') {
                    return -1;
                }
                if (typeof a !== 'number' && typeof b === 'number') {
                    return 1;
                }
                
                // 都不是数字，按字符串比较
                return String(a).localeCompare(String(b), 'zh-CN', {numeric: true});
            }
            
            updateHeaderStyles() {
                const headers = document.querySelectorAll('th');
                headers.forEach((header, index) => {
                    header.classList.remove('sort-asc', 'sort-desc');
                    if (index === this.sortColumn) {
                        header.classList.add(this.sortDirection === 'asc' ? 'sort-asc' : 'sort-desc');
                    }
                });
            }
            
            selectRow(index) {
                // 移除之前的选中状态
                const prevSelected = document.querySelector('tbody tr.selected');
                if (prevSelected) {
                    prevSelected.classList.remove('selected');
                }
                
                // 添加新的选中状态
                const rows = document.querySelectorAll('tbody tr');
                if (rows[index]) {
                    rows[index].classList.add('selected');
                    this.selectedRow = index;
                }
            }
            
            isSortingEnabled() {
                return true; // 可通过参数控制
            }
            
            onCellClick(row, col) {
                // 这里可以通过Qt桥接发送信号
            }
            
            onCellDoubleClick(row, col) {
                if (window.bridge) {
                    window.bridge.on_row_double_clicked(row);
                }
            }
        }
        
        // 初始化表格
        document.addEventListener('DOMContentLoaded', () => {
            window.modernTable = new ModernTable();
            var container = document.querySelector('.table-container');
            if (container) {
                container.addEventListener('scroll', function() {
                    window.bridge.on_scroll_changed(container.scrollLeft, container.scrollTop);
                });
            }
        });
        """
    
    def apply_style(self):
        """应用样式"""
        self._style_applied = True
    
    def _on_load_finished(self, ok):
        """Reapply stored sort state after page reload."""
        if ok and hasattr(self, '_current_sort_column') and self._current_sort_column >= 0:
            # Use timer to delay execution until JS objects are ready
            from PySide6.QtCore import QTimer
            QTimer.singleShot(100, self._reapply_sort)
    
    def _reapply_sort(self):
        """Reapply sort with delay to ensure JS is ready."""
        from loguru import logger
        if hasattr(self, '_current_sort_column') and self._current_sort_column >= 0:
            logger.info(f"尝试重新应用排序: 列{self._current_sort_column}, 方向{self._current_sort_direction}")
            js = f"""
            if (window.modernTable && window.modernTable.sortTable) {{
                console.log('重新应用排序: 列{self._current_sort_column}, 方向{self._current_sort_direction}');
                window.modernTable.sortTable({self._current_sort_column}, '{self._current_sort_direction}');
            }} else {{
                console.log('modernTable对象未准备好');
            }}
            """
            self.webview.page().runJavaScript(js)
            # Restore scroll position
            scroll_js = f'''
            (function() {{
                var container = document.querySelector('.table-container');
                if (container) {{
                    container.scrollLeft = {self._scroll_x};
                    container.scrollTop = {self._scroll_y};
                }}
            }})();
            '''
            self.webview.page().runJavaScript(scroll_js)
        
    def initialize(self):
        """初始化组件"""
        if not self._is_initialized:
            self.setup_ui()
            self.apply_style()
            self._is_initialized = True
    
    def update_data(self, headers=None, data=None):
        """
        更新表格的表头和数据。

        Args:
            headers (List[str], optional): 新的表头列表。如果为None，则不更新。
            data (List[List[Any]], optional): 新的表格数据。如果为None，则不更新。
        """
        from loguru import logger
        if headers is not None:
            self.headers = headers
        if data is not None:
            self.data = data
            # 如果有之前的排序状态，在Python端进行排序
            if hasattr(self, '_current_sort_column') and self._current_sort_column >= 0:
                logger.info(f"在Python端应用排序: 列{self._current_sort_column}, 方向{self._current_sort_direction}")
                self._sort_data_python(self._current_sort_column, self._current_sort_direction)
        
        self._render_table()
    
    def _sort_data_python(self, column_index, sort_direction):
        """在Python端对数据进行排序"""
        if not self.data or column_index >= len(self.headers):
            return
        
        def get_sort_key(row):
            if column_index >= len(row):
                return ""
            cell_value = str(row[column_index])
            # 尝试解析为数字
            try:
                # 移除百分号、千分位分隔符等
                sanitized = cell_value.replace('%', '').replace(',', '').replace(' ', '')
                if sanitized.replace('.', '').replace('-', '').replace('+', '').isdigit():
                    return float(sanitized)
            except:
                pass
            # 如果不是数字，返回字符串用于排序
            return cell_value.lower()
        
        reverse = (sort_direction == 'desc')
        self.data.sort(key=get_sort_key, reverse=reverse)
    
    def set_data(self, headers, data):
        """
        设置表格的表头和数据 (update_data的别名)。

        Args:
            headers (List[str]): 新的表头列表。
            data (List[List[Any]]): 新的表格数据。
        """
        self.update_data(headers, data)
    
    @Slot(int)
    def _on_row_double_clicked(self, row_index: int):
        """处理来自JS的双击事件"""
        if 0 <= row_index < len(self.data):
            row_data = self.data[row_index]
            data_dict = {header: value for header, value in zip(self.headers, row_data)}
            self.row_double_clicked.emit(data_dict)

    def _on_js_sort_changed(self, col_index, sort_direction):
        """Store sort state from JS."""
        from loguru import logger
        logger.info(f"排序状态变更: 列{col_index}, 方向{sort_direction}")
        self._current_sort_column = col_index
        self._current_sort_direction = sort_direction

    def _on_js_scroll_changed(self, scroll_left, scroll_top):
        """Store scroll position from JS."""
        self._scroll_x = scroll_left
        self._scroll_y = scroll_top

    def set_profit_loss_style(self, columns: Union[List[int], List[str]], use_gradient=False, color_type='font'):
        """
        设置盈亏样式列
        
        Args:
            columns: 列索引列表或列名列表
            use_gradient: 是否使用渐变效果，绝对值越大颜色越深
            color_type: 颜色类型，'font'为字体颜色，'background'为背景色
        """
        self._profit_loss_columns.clear()
        self._use_gradient = use_gradient
        self._color_type = color_type
        
        for col in columns:
            if isinstance(col, str):
                # 列名转换为索引
                try:
                    col_idx = self.headers.index(col)
                    self._profit_loss_columns.add(col_idx)
                except ValueError:
                    continue
            elif isinstance(col, int):
                # 直接是索引
                if 0 <= col < len(self.headers):
                    self._profit_loss_columns.add(col)
        
        # 重新渲染表格
        self._render_table()
    
    def enable_sorting(self, enable=True):
        """启用/禁用排序功能"""
        self._sorting_enabled = enable
        self._render_table()
    
    def set_column_resize_mode(self, mode='resizable'):
        """
        设置列宽调整模式
        
        Args:
            mode: 调整模式
                - 'resizable': 可调整列宽
                - 'fixed': 固定列宽
        """
        self._column_resize_mode = mode
        self._render_table()
    
    def add_row(self, row_data):
        """添加一行数据"""
        self.data.append(row_data)
        self._render_table()
    
    def remove_row(self, row_index):
        """删除指定行"""
        if 0 <= row_index < len(self.data):
            self.data.pop(row_index)
            self._render_table()
    
    def clear_data(self):
        """清空表格数据"""
        self.data.clear()
        self._render_table()
    
    def get_selected_row(self):
        """获取选中的行索引 (需要JavaScript桥接实现)"""
        # 这里需要通过JavaScript桥接来获取选中行
        return None
    
    def get_selected_data(self):
        """获取选中行的数据"""
        row_index = self.get_selected_row()
        if row_index is not None and 0 <= row_index < len(self.data):
            return self.data[row_index]
        return None
    
    def resize_columns_to_contents(self):
        """调整列宽以适应内容 (CSS自动处理)"""
        pass
    
    def set_editable(self, editable=True):
        """设置表格是否可编辑 (需要额外实现)"""
        # HTML表格的编辑需要额外的JavaScript实现
        pass
    
    def set_chart_column(self, column: Union[int, str], chart_config: Dict[str, Any] = None):
        """
        设置某一列显示小型折线图。

        单元格的数据应该是可迭代的数值（如列表、元组）或逗号分隔的字符串。

        Args:
            column (Union[int, str]): 要设置为图表列的列索引或列名。
            chart_config (Dict[str, Any], optional): 图表配置字典。 Defaults to None.
                - 'width' (int): 图表宽度 (默认 100)。
                - 'height' (int): 图表高度 (默认 30)。
                - 'positive_color' (str): 上涨颜色 (默认 '#4caf50')。
                - 'negative_color' (str): 下跌颜色 (默认 '#f44336')。
                - 'show_percent' (bool): 是否在数值后显示'%' (默认 False)。
                - 'color_style' (str): 颜色风格 (默认 None)。可选值：
                    - 'stock_profit': 股票盈亏风格，上涨红色，下跌绿色
        
        Raises:
            ValueError: 如果列名或索引无效。
        """
        # 获取列索引
        col_idx = column
        if isinstance(column, str):
            try:
                col_idx = self.headers.index(column)
            except ValueError:
                raise ValueError(f"列 '{column}' 不存在")
        elif isinstance(column, int):
            if not (0 <= column < len(self.headers)):
                raise ValueError(f"列索引 {column} 超出范围")
        
        # 设置默认配置
        default_config = {
            'width': 100,
            'height': 30,
            'stroke_width': 1,
            'color': '#2196f3',
            'positive_color': '#4caf50',
            'negative_color': '#f44336',
            'show_percent': False,
            'color_style': None
        }
        
        # 应用颜色风格预设
        if chart_config and chart_config.get('color_style') == 'stock_profit':
            default_config.update({
                'positive_color': '#f44336',  # 上涨红色
                'negative_color': '#4caf50'   # 下跌绿色
            })
        
        if chart_config:
            default_config.update(chart_config)
        
        self._chart_columns[col_idx] = default_config
        
        # 重新渲染表格
        self._render_table()
    
    def remove_chart_column(self, column: Union[int, str]):
        """移除图表列设置"""
        col_idx = column
        if isinstance(column, str):
            try:
                col_idx = self.headers.index(column)
            except ValueError:
                return
        
        if col_idx in self._chart_columns:
            del self._chart_columns[col_idx]
            self._render_table()
    
    def clear_chart_columns(self):
        """清除所有图表列设置"""
        self._chart_columns.clear()
        self._render_table()

    def set_hidden_columns(self, columns: Union[List[int], List[str]]):
        """
        设置要隐藏的列。

        Args:
            columns (Union[List[int], List[str]]): 要隐藏的列索引或列名列表。
        """
        self._hidden_columns.clear()
        for col in columns:
            if isinstance(col, str):
                try:
                    col_idx = self.headers.index(col)
                    self._hidden_columns.add(col_idx)
                except ValueError:
                    continue  # 如果列名不存在则忽略
            elif isinstance(col, int):
                if 0 <= col < len(self.headers):
                    self._hidden_columns.add(col)
        
        self._render_table()

    def set_fixed_height(self, height):
        """Set a fixed height for the HTML table widget."""
        self.setFixedHeight(height)